package userandright

import (
	"strings"

	"gitee.com/tomatomeatman/golang-repository/bricks3/model/globalvariable"
	"gitee.com/tomatomeatman/golang-repository/bricks3/utils/app/moduleutil"
	"gitee.com/tomatomeatman/golang-repository/bricks3/utils/sqlfactory"

	"gitee.com/tomatomeatman/golang-repository/bricks3/function/filecache"

	"github.com/gin-gonic/gin"
)

type UserAndRightService struct {
}

var (
	cUserRightOrdinary *filecache.FileCache //make(map[string][]string) //用户权限验证用缓存池(普通)
	cUserRightSpecial  *filecache.FileCache //make(map[string][]string) //用户权限验证用缓存池(特殊)
	cUserRightId       *filecache.FileCache
	cUserRightEnglist  *filecache.FileCache
)

func init() {
	service := &UserAndRightService{}
	go service.initCache() //初始化缓存
	globalvariable.Add("Module@UserAndRightService", service)
}

// 初始化缓存
func (service *UserAndRightService) initCache() {
	cUserRightOrdinary, _ = filecache.GetCheck("./temp/cache/UserAndRight/UrlOrdinary.gob", -1, false) //用户权限验证用缓存池(普通)
	cUserRightSpecial, _ = filecache.GetCheck("./temp/cache/UserAndRight/UrlSpecial.gob", -1, false)   //用户权限验证用缓存池(特殊)
	cUserRightId, _ = filecache.GetCheck("./temp/cache/UserAndRight/RightId.gob", -1, false)           //用户权限Id用缓存池
	cUserRightEnglist, _ = filecache.GetCheck("./temp/cache/UserAndRight/RightEnglist.gob", -1, false) //用户权限英文标识用缓存池
}

/**
 * 验证指定用户是否有访问指定url的权限
 * @param sUserId 验证的用户
 * @param url 请求验证的权限(URL地址)
 * @return
 */
func (service UserAndRightService) CheckRight(ctx *gin.Context, sUserId, url string) (bool, string, interface{}) {
	if sUserId == "" {
		return false, "待验证的用户编号为空", 8001
	}

	if url == "" {
		return false, "待验证的访问权限为空", 8002
	}

	if sUserId == "00000000" || sUserId == "00000001" {
		return true, "管理员账号,不受限", true
	}

	urlOrdinary := ";" + url + ";" //添加前后缀以免误判

	//--先判断普通权限,普通权限的前后都加有';'--//

	var list []string
	_, ok := cUserRightOrdinary.Get(sUserId, &list)
	if ok && (len(list) > 0) {
		for _, val := range list {
			if strings.Contains(val, urlOrdinary) {
				return true, "有权限", true
			}
		}
	}

	if len(list) < 1 {
		bl, msg, res := service.LoadRight(sUserId) //读取指定用户的权限
		if !bl {
			return bl, msg, res
		}

		b := false
		array := []string{}
		simplRights := res.([]SimpleRight)
		for _, simplRight := range simplRights {
			if simplRight.GsControllerPath == "" {
				continue
			}

			temp := strings.Split(simplRight.GsControllerPath, ";")
			for _, v := range temp {
				if (v == "") || strings.Contains(v, "*") {
					continue
				}

				v = ";" + v + ";"
				array = append(array, v)
				if strings.Contains(v, urlOrdinary) {
					b = true
				}
			}
		}

		var Array []string
		_, ok := cUserRightOrdinary.Get(sUserId, &Array)
		if ok {
			Array = append(Array, array...)

			cUserRightOrdinary.Set(Array, sUserId)
		} else {
			cUserRightOrdinary.Set(array, sUserId)
		}

		if b {
			return true, "有权限", true
		}
	}

	//--普通权限没有则查找通配符方式,通配符方式权限的前后没有加';'--//
	urlOrdinary = url //重新回到URL
	var list2 []string
	_, ok = cUserRightSpecial.Get(sUserId, &list2)
	if ok && (len(list2) > 0) {
		for _, val := range list2 {
			if strings.HasPrefix(urlOrdinary, val) { //判断是否以'val'为开头
				return true, "有权限", 8999
			}
		}
	}

	if len(list2) < 1 {
		bl, msg, res := service.LoadRight(sUserId) //读取指定用户的权限
		if !bl {
			return bl, msg, res
		}

		b := false
		array := []string{}
		simplRights := res.([]SimpleRight)
		for _, simplRight := range simplRights {
			if simplRight.GsControllerPath == "" {
				continue
			}

			temp := strings.Split(simplRight.GsControllerPath, ";")
			for _, v := range temp {
				if (v == "") || !strings.Contains(v, "*") {
					continue
				}

				iEd := strings.Index(v, "*")
				array = append(array, v[:iEd])
				if strings.HasPrefix(urlOrdinary, v) {
					b = true
				}
			}
		}

		var Array []string
		_, ok := cUserRightSpecial.Get(sUserId, &Array)
		if ok {
			Array = append(Array, array...)
			cUserRightSpecial.Set(Array, sUserId)
		} else {
			cUserRightSpecial.Set(array, sUserId)
		}

		if b {
			return true, "有权限", 8999
		}
	}

	return false, "无权权访问:" + url, 8004
}

/**
 * 读取指定用户的权限,并返回权限集合
 * @param sUserId
 * @return
 */
func (service UserAndRightService) LoadRight(sUserId string) (bool, string, interface{}) {
	bl, msg, res := service.findRightListByInit(sUserId) //根据用户读取用户对应的所有权限,注意:只返回了3个值sRightId/sEnglish/sControllerPath
	if !bl {
		return bl, msg, res
	}

	list := res.([]SimpleRight)
	if len(list) < 1 {
		return false, "未查询到用户相关权限信息!", 8100
	}

	service.crateRightCache(list, sUserId)

	return true, "在数据库中找到", list //返回结果
}

/**
 * 初始化查询权限信息集合
 * @param sUserId
 * @return
 */
func (service UserAndRightService) findRightListByInit(sUserId string) (bool, string, interface{}) {
	var build strings.Builder
	build.WriteString(" SELECT")
	build.WriteString(" 	RightInfo.sRightId,")
	build.WriteString(" 	RightInfo.sEnglish,")
	build.WriteString(" 	RightInfo.sControllerPath")
	build.WriteString(" FROM ")

	where := map[string]interface{}{}

	if (sUserId != "") && (strings.Contains("/00000000/00000001/", "/"+sUserId+"/")) {
		build.WriteString(" 	RightInfo")
	} else {
		build.WriteString(" 	RightInfo, UserAndRight")
		build.WriteString(" WHERE RightInfo.sRightId = UserAndRight.sRightId")
		build.WriteString(" 	AND UserAndRight.sUserId = @sUserId ")
		build.WriteString(" UNION")
		build.WriteString(" SELECT ")
		build.WriteString(" 	sRightId,")
		build.WriteString(" 	sEnglish,")
		build.WriteString(" 	sControllerPath ")
		build.WriteString(" FROM RightInfo")
		build.WriteString(" WHERE sRightId IN (")
		build.WriteString(" 	select sRightId from RoleAndRight")
		build.WriteString(" 	where RoleAndRight.sRoleId in (")
		build.WriteString(" 		select a.sRoleId from UserAndRole a")
		build.WriteString(" 		where a.sUserId = @sUserId")
		build.WriteString(" 	)")
		build.WriteString(" )")

		where["sUserId"] = sUserId
	}

	txt := build.String()

	var list []SimpleRight
	bl, msg, res := sqlfactory.Find(moduleutil.GetMainDb(), &list, txt, where)
	if !bl {
		return bl, msg, res
	}

	return true, "查询成功", list
}

/**
 * 创建缓存
 */
func (service UserAndRightService) crateRightCache(list []SimpleRight, sUserId string) (bool, string, interface{}) {
	if len(list) < 1 {
		return false, "数据有错", 8100
	}

	cUserRightOrdinary.Clear() //用户权限验证用缓存池(普通)
	cUserRightSpecial.Clear()  //用户权限验证用缓存池(特殊)
	cUserRightId.Clear()       //用户权限Id用缓存池
	cUserRightEnglist.Clear()  //用户权限英文标识用缓存池

	var sbEnglist strings.Builder
	listRightId := map[string]string{}
	listUrlsOrdinary := map[string]string{}
	listUrlsSpecial := map[string]string{}

	for _, simpleRight := range list {
		sbEnglist.WriteString(simpleRight.GsEnglish)
		sbEnglist.WriteString("/")
		listRightId[simpleRight.GsRightId] = ""

		temp := strings.TrimSpace(simpleRight.GsControllerPath)
		if temp == "" {
			continue
		}

		array := strings.Split(temp, ";")
		for _, val := range array {
			val = strings.TrimSpace(val)
			if (val == "") || (val == "-") {
				continue
			}

			str := ";" + val + ";"
			_, ok := listUrlsOrdinary[str]
			if (!strings.Contains(val, "*")) && (!ok) {
				listUrlsOrdinary[str] = ""
				continue
			}

			_, ok = listUrlsSpecial[val]
			if (strings.Contains(val, "*")) && (!ok) {
				iEd := strings.Index(val, "*")
				listUrlsSpecial[val[:iEd]] = ""
				continue
			}
		}
	}

	array := []string{}
	for key := range listUrlsOrdinary {
		array = append(array, key)
	}
	cUserRightOrdinary.Set(array, sUserId) //用户权限验证用缓存池(普通)

	array = []string{}
	for key := range listUrlsSpecial {
		array = append(array, key)
	}
	cUserRightSpecial.Set(array, sUserId) //用户权限验证用缓存池(特殊)

	array = []string{}
	for key := range listRightId {
		array = append(array, key)
	}

	cUserRightId.Set(array, sUserId)

	cUserRightEnglist.Set(sbEnglist.String(), sUserId)

	return true, "创建缓存成功", 8999 //返回结果
}

/**
 * 根据用户查询用户所拥有的权限编号集合
 * @param sUserId
 * @return
 */
func (service UserAndRightService) FindRightId(sUserId string) (bool, string, interface{}) {
	sUserId = strings.TrimSpace(sUserId)
	if sUserId == "" {
		return false, "用户编号不能为空", 8001
	}

	var array []string
	_, ok := cUserRightId.Get(sUserId, &array)
	if ok && len(array) > 0 {
		return true, "查询成功", array
	}

	bl, msg, res := service.LoadRight(sUserId) //读取指定用户的权限
	if !bl {
		return bl, msg, res
	}

	_, ok = cUserRightId.Get(sUserId, &array)
	if !ok {
		return bl, msg, res.(int) + 10
	}

	return true, "查询成功", array
}

/**
 * 根据用户取权限标识字符串(一个权限标识代表了多个可访问的url路径)
 * @param sUserId
 * @return
 */
func (service UserAndRightService) FindEnglishByUserId(sUserId string) (bool, string, interface{}) {
	sUserId = strings.TrimSpace(sUserId)
	if sUserId == "" {
		return false, "用户编号不能为空", 8001
	}

	var result string
	_, ok := cUserRightEnglist.Get(sUserId, &result)
	if ok && result != "" {
		return true, "查询成功", result
	}

	bl, msg, res := service.LoadRight(sUserId) //读取指定用户的权限
	if !bl {
		return bl, msg, res
	}

	_, ok = cUserRightEnglist.Get(sUserId, &result)
	if !ok {
		return false, "没有找到用户对应的权限", 8002
	}

	return true, "查询成功", result
}
